<script setup lang="ts">
import { PaymentMethod } from '@/enums'
import {
  createConsultOrder,
  getConsultOrderPre,
  getPayUrl
} from '@/services/consult'
import { getPatientDetail } from '@/services/user'
import { useConsultStore } from '@/stores'
import type { ConsultOrderPreData } from '@/types/consult'
import type { Patient } from '@/types/user'
import type { AxiosError } from 'axios'
import {
  showConfirmDialog,
  showDialog,
  showLoadingToast,
  showToast
} from 'vant'
import { onMounted, ref } from 'vue'
import { onBeforeRouteLeave, useRouter } from 'vue-router'

const consultStore = useConsultStore()

// #region 获取预支付金额数据
const consultOrderPreData = ref<ConsultOrderPreData>()
const getConsultOrderPreData = async () => {
  consultOrderPreData.value = await getConsultOrderPre({
    type: consultStore.consult.type,
    illnessType: consultStore.consult.illnessType
  })
}
// #endregion

// #region 获取患者信息
const patient = ref<Patient>()
const getPatient = async () => {
  patient.value = await getPatientDetail(
    consultStore.consult.patientId as string
  )
}
// #endregion

onMounted(() => {
  getConsultOrderPreData()
  getPatient()
})

// 是否同意协议
const agree = ref(false)

// 是否正在加载中（预支付）（生成订单id）
const loadingOfPrePay = ref(false)

// 预支付
const prePay = async () => {
  if (!agree.value) return showToast('请同意支付协议')

  // 显示加载中效果
  loadingOfPrePay.value = true
  // 生成订单id
  consultStore.orderId = await createConsultOrder(consultStore.consult)
  // 停止加载中效果
  loadingOfPrePay.value = false

  // 弹出支付方式抽屉
  show.value = true
}

// 是否显示支付方式抽屉（如果有订单id，那么就直接显示）
const show = ref(consultStore.orderId !== '' ? true : false)

// 用 hook 函数 获取路由器实例
const router = useRouter()

const onBeforeClose = async () => {
  try {
    await showConfirmDialog({
      title: '关闭支付',
      message: '取消支付将无法获得医生回复，医生接诊名额有限，是否确认关闭？',
      confirmButtonText: '继续支付',
      cancelButtonText: '仍要关闭',
      closeOnPopstate: false // 是否在页面回退时自动关闭
    })
    // 点的是确定按钮（继续支付）
    return false // 可以阻止动作面板关闭
  } catch (err) {
    // 点的是取消按钮（仍要关闭）
    // 跳走前，删除订单id 和 问诊信息
    consultStore.orderId = ''
    consultStore.clearConsult()
    // 去问诊记录页面
    router.push('/user/consult')
    return true
  }
}

// 在路由跳转离开前
onBeforeRouteLeave(() => {
  // return false // 阻止离开，过程：先触发后退 => 中途拦截阻止 => 再前进跳回原来的页面
  // return true 或者 不 return // 允许离开

  if (consultStore.orderId) {
    // onBeforeClose()
    // 要在阻止路由跳转之后 再弹出对话框
    // 阻止路由的动作时（先跳过去了，但是中途被拦住了，又跳回来了）（能够看到地址栏其实是有闪动的）
    return false
  }
})

const paymentMethod = ref<PaymentMethod>()

const pay = async () => {
  if (paymentMethod.value === undefined) {
    return showToast('请选择支付方式')
  }

  // 同一时间，只会有一个 toast 显示
  showLoadingToast({
    message: '支付跳转中...',
    duration: 0 // 0 表示一直显示，直到手动关闭为止，默认 2000ms
  })

  try {
    // 发请求，获取支付地址
    const payUrl = await getPayUrl({
      orderId: consultStore.orderId,
      paymentMethod: paymentMethod.value,
      // 这个回跳要给完整地址，因为是从支付宝跳回来的
      payCallback: 'http://127.0.0.1:5173/room' // 支付完成后的回跳地址，根据业务逻辑，应该跳到问诊室去
    })

    // 然后清空问诊信息和订单id
    consultStore.clearConsult()
    consultStore.orderId = ''

    // 然后跳转支付
    // 跳的是别人的网站了，要用这种方式，不能用 router.push 了
    window.location.href = payUrl
  } catch (err) {
    // 当出现异常时，要关闭加载中效果
    // toastInstance.close()
    // toast 还有一个特性：后面的会顶掉前面的，所以这里不需要手动关闭，因为响应拦截器中，错误提示会顶掉那个加载中toast

    if (
      (err as AxiosError<{ message: string }>).response?.data.message ===
      '订单信息错误，请检查参数'
    ) {
      await showDialog({
        title: '温馨提示',
        message: '订单支付已超时，请重新提交订单！'
      })
      // 订单id要清除，要重新生成订单id了
      consultStore.orderId = ''
      // 问诊信息不用清除，方便用户接着上次的填
      router.push({ name: 'HomeIndex' })
    }
  }
}
</script>

<template>
  <div class="consult-pay-page">
    <cp-nav-bar title="支付" />
    <div class="pay-info">
      <p class="tit">图文问诊 {{ consultOrderPreData?.payment }} 元</p>
      <img class="img" src="@/assets/avatar-doctor.svg" />
      <p class="desc">
        <span>极速问诊</span>
        <span>自动分配医生</span>
      </p>
    </div>
    <van-cell-group>
      <van-cell
        title="优惠券"
        :value="`-¥${consultOrderPreData?.couponDeduction}`"
      />
      <van-cell
        title="积分抵扣"
        :value="`-¥${consultOrderPreData?.pointDeduction}`"
      />
      <van-cell
        title="实付款"
        :value="`¥${consultOrderPreData?.actualPayment}`"
        class="pay-price"
      />
    </van-cell-group>
    <div class="pay-space"></div>
    <van-cell-group>
      <van-cell
        title="患者信息"
        :value="`${patient?.name} | ${patient?.genderValue} | ${patient?.age}岁`"
      ></van-cell>
      <van-cell
        title="病情描述"
        :label="consultStore.consult.illnessDesc"
      ></van-cell>
    </van-cell-group>
    <div class="pay-schema">
      <van-checkbox v-model="agree"
        >我已同意 <span class="text">支付协议</span></van-checkbox
      >
    </div>
    <van-submit-bar
      button-type="primary"
      :price="
        consultOrderPreData?.actualPayment as number * 100
      "
      button-text="立即支付"
      text-align="left"
      @submit="prePay"
      :loading="loadingOfPrePay"
    />
  </div>

  <!-- closeable 是否显示右上角的关闭图标 -->
  <!-- before-close 关闭之前的回调，return false 可以阻止关闭，支持 Promise -->
  <!-- 
    close-on-popstate 是否在路由回退时关闭，默认 true
    补充说明：其实 popstate 是 h5 history 的事件，这个事件只要是访问历史记录中的路由，都会触发，后退前进都有可能触发
  -->
  <!--
    后退用户引导：
      需求：
        1. 如果生成了订单id，就阻止后退
        2. 在阻止后退时，要弹出关闭支付确认对话框，引导用户继续支付
      逻辑：
        1. 当用户点击后退时，action-sheet 会自动关闭，因为 close-on-popstate 的默认值为 true
        2. 既然会关闭，就会触发 before-close 回调
        3. 既然触发了 before-close 回调，就会弹出关闭支付确认对话框，引导用户继续支付
        4. 但是，由于：
          4.1. onBeforeRouteLeave 会阻止路由离开，并且阻止的过程是：先触发后退 => 中途拦截阻止 => 再前进跳回到原来的路由，这个过程中其实有两次路由变化
          4.2. 第一次路由变化（后退）：会触发上述逻辑中的第一步，从而联带的触发第二步和第三步逻辑，最终弹出关闭支付确认对话框
          4.3. 第二次路由变化（前进跳回）：由于 Dialog 组件也会在触发 popstate 的时候自动关闭，因为 closeOnPopstate 默认值为 true，所以，你会看到闪一下，弹出来之后又会马上关闭
          4.4. 所以，咱们只需要让关闭支付对话框在 popstate 的时候不自动关闭即可
   -->
  <van-action-sheet
    v-model:show="show"
    title="选择支付方式"
    :closeable="false"
    :before-close="onBeforeClose"
  >
    <div class="pay-type">
      <p class="amount">
        ￥{{ consultOrderPreData?.actualPayment.toFixed(2) }}
      </p>
      <van-cell-group>
        <van-cell
          title="微信支付"
          @click="paymentMethod = PaymentMethod.WeChat"
        >
          <template #icon><cp-icon name="consult-wechat" /></template>
          <template #extra
            ><van-checkbox :modelValue="paymentMethod === PaymentMethod.WeChat"
          /></template>
        </van-cell>
        <van-cell
          title="支付宝支付"
          @click="paymentMethod = PaymentMethod.Alipay"
        >
          <template #icon><cp-icon name="consult-alipay" /></template>
          <template #extra
            ><van-checkbox :modelValue="paymentMethod === PaymentMethod.Alipay"
          /></template>
        </van-cell>
      </van-cell-group>
      <div class="btn">
        <van-button type="primary" round block @click="pay"
          >立即支付</van-button
        >
      </div>
    </div>
  </van-action-sheet>
</template>

<style lang="scss" scoped>
.consult-pay-page {
  padding: 46px 0 50px 0;
}
.pay-info {
  display: flex;
  padding: 15px;
  flex-wrap: wrap;
  align-items: center;
  .tit {
    width: 100%;
    font-size: 16px;
    margin-bottom: 10px;
  }
  .img {
    margin-right: 10px;
    width: 38px;
    height: 38px;
    border-radius: 4px;
    overflow: hidden;
  }
  .desc {
    flex: 1;
    > span {
      display: block;
      color: var(--cp-tag);
      &:first-child {
        font-size: 16px;
        color: var(--cp-text2);
      }
    }
  }
}
.pay-price {
  ::v-deep() {
    .vam-cell__title {
      font-size: 16px;
    }
    .van-cell__value {
      font-size: 16px;
      color: var(--cp-price);
    }
  }
}
.pay-space {
  height: 12px;
  background-color: var(--cp-bg);
}
.pay-schema {
  height: 56px;
  display: flex;
  align-items: center;
  justify-content: center;
  .text {
    color: var(--cp-primary);
  }
}
::v-deep() {
  .van-submit-bar__button {
    font-weight: normal;
    width: 160px;
  }
}
.pay-type {
  .amount {
    padding: 20px;
    text-align: center;
    font-size: 16px;
    font-weight: bold;
  }
  .btn {
    padding: 15px;
  }
  .van-cell {
    align-items: center;
    .cp-icon {
      margin-right: 10px;
      font-size: 18px;
    }
    .van-checkbox :deep(.van-checkbox__icon) {
      font-size: 16px;
    }
  }
}
</style>
